基于Halcon的MFC窗口实现读图检测显示数据的功能

您所在的位置:网站首页 mfc 文本框赋值 基于Halcon的MFC窗口实现读图检测显示数据的功能

基于Halcon的MFC窗口实现读图检测显示数据的功能

2024-07-12 23:45:59| 来源: 网络整理| 查看: 265

前言

现在视觉检测在工业自动化生产中得到了越来越广泛的使用,主流的视觉检测软件有德国的HALCON,美国康耐视的Vision Pro,以及OpenCV。但是客户使用的时候是不想看到大量代码和算子的,所以我们需要利用设计窗口界面的软件来搭建与用户交互的平台,常用的有QT,MFC等,这里我们利用Halcon+MFC来实现这一个小功能。

项目介绍

需要两个显示图像的窗口,一个窗口用来读取待检测的图片,另一个窗口用来显示检测的结果,客户可以根据自己的需求定义需要检测的ROI,实现检测绘框内的缺陷,返回计算的平均灰度以及最小最大灰度。(需要在窗口中响应鼠标的坐标值以及相应的灰度)。

Halcon内部实现功能

在这里插入图片描述 导出为C++格式的代码,开始进行我们MFC应用程序的搭建。

MFC应用程序的搭建

首先配置Halcon的环境,具体见MFC下配置Halcon环境然后再我们的Dailog下添加如下图所示的控件,定义自己的控件ID。(检测结果下方为静态文本框) 在这里插入图片描述 这里的静态文本框ID不能使用IDC_STATIC,需要重新命名。

在这里插入图片描述

功能实现模块

首先我们给静态文本框添加一个静态变量(名称:m_ctShow2)

在这里插入图片描述 给我们的图片控制窗口添加变量(名称:m_ctlShow4)

在这里插入图片描述 首先我们来实现第一个功能读取图片:

Dlg.h 中声明对象与方法:

class CHalconCxyDlg : public CDialog { // 构造 public: CHalconCxyDlg(CWnd* pParent = NULL); // 标准构造函数 // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_HALCONCXY_DIALOG }; #endif protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 // 实现 protected: HICON m_hIcon; // 生成的消息映射函数 virtual BOOL OnInitDialog(); afx_msg void OnSysCommand(UINT nID, LPARAM lParam); afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); DECLARE_MESSAGE_MAP() public: /*声明Htuple 的变量与HObject 的变量*/ HTuple Handle1, Handle2,h_filepath,h_Width,h_Height, hv_Value, hv_Min, hv_Max, hv_Range, hv_Area_1, hv_Row, hv_Column; HTuple h_Row1, h_Col1, h_Row2, h_Col2, hv_Area_2, hv_Row3, hv_Column3,Num; HObject ho_image,ho_rectangle, ho_ImagePart, ho_Regions, ho_ConnectedRegions, ho_SelectedRegions, ho_ImageReduced; void DisImage(HObject Image, HTuple WindowHandle); //显示图片方法 public: //CStatic m_ctlShow1; CString Filepath; //文件夹变量 CString str; CStatic m_ctlShow2; //静态文本框变量 CStatic m_ctlShow4; //图片控制框变量 double m_dScale; //缩放倍数 CPoint m_ptStart; //鼠标拖动的起点 CPoint m_ptEnd; //鼠标拖动的终点 int m_nHeightOffset; //偏移量 int m_nWidthOffset; //偏移量 afx_msg void OnBnClickedOk(); //打开开关响应函数 afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt); //鼠标滚轮响应函数 afx_msg BOOL PreTranslateMessage(MSG* pMsg); //鼠标按键消息响应函数 };

Dlg.cpp中定义方法以及初始化显示图像的窗口:

#include "stdafx.h" #include "HalconCxy.h" #include "HalconCxyDlg.h" #include "afxdialogex.h" #ifdef _DEBUG #define new DEBUG_NEW #endif // 用于应用程序“关于”菜单项的 CAboutDlg 对话框 class CAboutDlg : public CDialogEx { public: CAboutDlg(); // 对话框数据 #ifdef AFX_DESIGN_TIME enum { IDD = IDD_ABOUTBOX }; #endif protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 // 实现 protected: DECLARE_MESSAGE_MAP() }; CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX) { } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx) END_MESSAGE_MAP() // CHalconCxyDlg 对话框 CHalconCxyDlg::CHalconCxyDlg(CWnd* pParent /*=NULL*/) : CDialog(IDD_HALCONCXY_DIALOG, pParent) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CHalconCxyDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //DDX_Control(pDX, IDC_STATIC_PICTURE_OPEN, m_ctlShow1); DDX_Control(pDX, IDC_STATIC_RESULT, m_ctlShow2); //DDX_Control(pDX, IDCANCEL, m_ctlShow3); DDX_Control(pDX, IDC_STATIC_PIC_CON, m_ctlShow4); } BEGIN_MESSAGE_MAP(CHalconCxyDlg, CDialog) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(IDOK, &CHalconCxyDlg::OnBnClickedOk) //打开按钮响应函数初始化 ON_WM_MOUSEWHEEL() //鼠标消息响应初始化 END_MESSAGE_MAP() // CHalconCxyDlg 消息处理程序 BOOL CHalconCxyDlg::OnInitDialog() { CDialog::OnInitDialog(); // 将“关于...”菜单项添加到系统菜单中。 // IDM_ABOUTBOX 必须在系统命令范围内。 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动 // 执行此操作 SetIcon(m_hIcon, TRUE); // 设置大图标 SetIcon(m_hIcon, FALSE); // 设置小图标 // TODO: 在此添加额外的初始化代码 /*开窗口*/ CRect rct1; m_ctlShow4.GetWindowRect(rct1); //获取控件窗口 CRect rct2; m_ctlShow2.GetWindowRect(rct2); //获取控件窗口 /*定义长整型的窗口句柄、窗口宽度和高度并初始化*/ long IWindowID1 = 0; long IWindowID2 = 0; long m_PicWidth = rct1.Width(); //获取窗口1宽度 long m_PicHeight = rct1.Height(); //获取窗口1高度 long m_ResWidth = rct2.Width(); //获取窗口2宽度 long m_ResHeight = rct2.Height(); //获取窗口2高度 //获取控件窗口句柄 IWindowID1 = (long)m_ctlShow4.GetSafeHwnd(); IWindowID2 = (long)m_ctlShow2.GetSafeHwnd(); //定义窗口初始化的背景颜色 SetWindowAttr("background_color","black"); //调用Halcon打开窗口函数 OpenWindow(0, 0, (long)m_PicWidth, (long)m_PicHeight, IWindowID1, "visible", "", &Handle1); OpenWindow(0, 0, (long)m_ResHeight, (long)m_ResWidth, IWindowID2, "visible", "", &Handle2); return TRUE; // 除非将焦点设置到控件,否则返回 TRUE } void CHalconCxyDlg::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xFFF0) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal(); } else { CDialog::OnSysCommand(nID, lParam); } } // 如果向对话框添加最小化按钮,则需要下面的代码 // 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序, // 这将由框架自动完成。 void CHalconCxyDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // 用于绘制的设备上下文 SendMessage(WM_ICONERASEBKGND, reinterpret_cast(dc.GetSafeHdc()), 0); // 使图标在工作区矩形中居中 int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // 绘制图标 dc.DrawIcon(x, y, m_hIcon); } else { CDialog::OnPaint(); } } //当用户拖动最小化窗口时系统调用此函数取得光标 //显示。 HCURSOR CHalconCxyDlg::OnQueryDragIcon() { return static_cast(m_hIcon); } /*利用Halcon中显示图像的方法进行显示图像的操作*/ void CHalconCxyDlg::DisImage(HObject Image, HTuple WindowHandle) { if (!Image.IsInitialized()) { return; } HTuple hImageWidth; //图片原始宽度 HTuple hImageHeight;//图片原始高度 GetImageSize(Image, &hImageWidth, &hImageHeight); int nImageHeight = hImageHeight.I(); int nImageWidth = hImageWidth.I(); /*一下逻辑为了满足图像在窗口中放大缩小操作*/ double Row1 = nImageHeight * m_dScale - m_nHeightOffset; double Column1 = nImageWidth * m_dScale - m_nWidthOffset; double Row2 = nImageHeight - nImageHeight * m_dScale - m_nHeightOffset; double Column2 = nImageWidth - nImageWidth * m_dScale - m_nWidthOffset; ClearWindow(WindowHandle); SetPart(WindowHandle, Row1, Column1, Row2, Column2); DispObj(Image, WindowHandle); } /*打开文件夹选择检测图像方法功能实现*/ void CHalconCxyDlg::OnBnClickedOk() { // TODO: 在此添加控件通知处理程序代码 CFileDialog Dlg(TRUE, L"", L"", OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, L"BMP文件(*.bmp)|*.bmp|JPG文件(*.jpg)|*.jpg|PNG文件(*.png)|*.png||", NULL); if (Dlg.DoModal() == IDOK) { Filepath = Dlg.GetPathName(); if (Filepath == "") { return; } } else { return; } h_filepath[0] = Filepath.GetBuffer(0); ReadImage(&ho_image, h_filepath); Filepath.ReleaseBuffer(); m_dScale = 0; //重置放缩比例 m_nHeightOffset = 0; //重置高度公差值 m_nWidthOffset = 0; //重置宽度公差值 DisImage(ho_image, Handle1); //调用显示图像的函数 } /*鼠标滚轮响应消息函数*/ BOOL CHalconCxyDlg::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) { // TODO: 在此添加消息处理程序代码和/或调用默认值 double dAddScal = 0.01; if (zDelta>0) { if (fabs(m_dScale + dAddScal - 0.5)>1e-6) { m_dScale += dAddScal; DisImage(ho_image, Handle1); } } else { if (fabs(m_dScale - dAddScal + 2)>1e-6) { m_dScale -= dAddScal; DisImage(ho_image, Handle1); } } return CDialog::OnMouseWheel(nFlags, zDelta, pt); } /*鼠标按钮响应函数*/ BOOL CHalconCxyDlg::PreTranslateMessage(MSG * pMsg) { if (pMsg->message == WM_LBUTTONDOWN) //当鼠标左键按下进行图片的放大缩小与移动 { CPoint point; GetCursorPos(&point); CPoint pt = point; ScreenToClient(&pt); CRect rc; m_ctlShow4.GetClientRect(&rc); if (rc.PtInRect(pt)) { m_ptStart = pt; m_ptEnd = pt; } } else if (pMsg->message == WM_LBUTTONUP) //当鼠标左键在上方显示当前变化后的图像 { CPoint point; GetCursorPos(&point); CPoint pt = point; ScreenToClient(&pt); CRect rc; m_ctlShow4.GetClientRect(&rc); if (rc.PtInRect(pt)) { m_ptEnd = pt; m_nWidthOffset += (m_ptEnd.x - m_ptStart.x); m_nHeightOffset += (m_ptEnd.y - m_ptStart.y); DisImage(ho_image, Handle1); } } else if (pMsg->message == WM_RBUTTONDOWN) //当鼠标右键按下显示坐标值和灰度值 { CPoint point; GetCursorPos(&point); CPoint pt = point; ScreenToClient(&pt); CRect rc; CWnd *pWnd = GetDlgItem(IDC_STATIC_PIC_CON); pWnd->GetWindowRect(&rc); ScreenToClient(&rc); GetCursorPos(&point); //获取鼠标 int temp_x = point.x; int temp_y = point.y; pWnd->ScreenToClient(&point); int x = point.x; int y = point.y; HDC hDC = ::GetDC(NULL); COLORREF rgb = ::GetPixel(hDC, temp_x, temp_y); int r = GetRValue(rgb); int g = GetGValue(rgb); int b = GetBValue(rgb); str.Format(L"坐标:X:%d,Y:%d 灰度:R:%d,G:%d,B:%d", x, y, r, g, b); //定义需要显示的字符串样式 GetDlgItem(IDC_STATIC_VALUE)->SetWindowText(str); //显示在静态文本框中 } return CDialog::PreTranslateMessage(pMsg); }

这下我们就完成了读图图片的操作(可以读图大图保持不失真)我们来看看效果:

在这里插入图片描述

然后我们开始进行ROI(绘制检测区域)按钮的功能实现,我们基于Halcon的图像处理库,可以直接使用DrawRectangle1(Handle1, &h_Row1, &h_Col1, &h_Row2, &h_Col2);来实现此功能。

同样在Dlg.h中声明变量和方法:

public: public: /*声明Htuple 的变量与HObject 的变量*/ HTuple Handle1, Handle2,h_filepath,h_Width,h_Height, hv_Value, hv_Min, hv_Max, hv_Range, hv_Area_1, hv_Row, hv_Column; HTuple h_Row1, h_Col1, h_Row2, h_Col2, hv_Area_2, hv_Row3, hv_Column3,Num; HObject ho_image,ho_rectangle, ho_ImagePart, ho_Regions, ho_ConnectedRegions, ho_SelectedRegions, ho_ImageReduced; void DisImage(HObject Image, HTuple WindowHandle); //显示图片 /*新增方法*/ void DrawRegion(); //绘制检测区域矩形 afx_msg void OnBnClickedButton2(); //ROI按钮响应函数

Dlg.cpp中定义方法

void CHalconCxyDlg::DrawRegion() { SetColor(Handle1, "blue"); DrawRectangle1(Handle1, &h_Row1, &h_Col1, &h_Row2, &h_Col2); GenRectangle1(&ho_rectangle, h_Row1, h_Col1, h_Row2, h_Col2); DispObj(ho_rectangle, Handle1); ReduceDomain(ho_image, ho_rectangle, &ho_ImageReduced); //CropDomain(ho_ImageReduced, &ho_ImagePart); double X1 = h_Row1; double Y1 = h_Col1; double X2 = h_Row2; double Y2 = h_Col2; ClearWindow(Handle2); SetPart(Handle2, X1, Y1, X2, Y2); DispObj(ho_ImageReduced, Handle2); } /*掉用按钮响应实现功能*/ void CHalconCxyDlg::OnBnClickedButton2() { // TODO: 在此添加控件通知处理程序代码 if (Filepath == "") { AfxMessageBox(L"请先加载图片", MB_ICONERROR); return; } else { DrawRegion(); } }

我们看下效果:

在这里插入图片描述 最后我们开始对检测按钮进行功能的实现:

Dlg.h中声明变量方法:

public: /*检测按钮消息响应函数*/ afx_msg void OnBnClickedButtonChack();

Dlg.cpp中实现功能

void CHalconCxyDlg::OnBnClickedButtonChack() { // TODO: 在此添加控件通知处理程序代码 if (Filepath == "") { AfxMessageBox(L"请先加载图片", MB_ICONERROR); return; } else { /* HTuple hv_Value, hv_Min, hv_Max;*/ GrayFeatures(ho_rectangle, ho_image, "mean", &hv_Value); MinMaxGray(ho_rectangle, ho_image, 0, &hv_Min, &hv_Max, &hv_Range); Threshold(ho_ImageReduced, &ho_Regions, hv_Value + 12, 255); AreaCenter(ho_Regions, &hv_Area_1, &hv_Row, &hv_Column); Connection(ho_Regions, &ho_ConnectedRegions); SelectShape(ho_ConnectedRegions, &ho_SelectedRegions, "area", "and", 6, 99999999); CountObj(ho_SelectedRegions, &Num); AreaCenter(ho_SelectedRegions, &hv_Area_2, &hv_Row3, &hv_Column3); int AgvValue = hv_Value.D(); //将HTuple hv_Value 转换为Double类型赋值给int类型的AgvValue int MinValue = hv_Min.D(); //将HTuple hv_Min 转换为Double类型赋值给int类型的MinValue int MaxValue = hv_Max.D(); //将HTuple hv_Max 转换为Double类型赋值给int类型的MaxValue if (Num>=1) { SetColor(Handle2, "red"); //定义缺陷的区域颜色为红色 DispObj(ho_SelectedRegions, Handle2); DispText(Handle2,"NG","window","top","left","red","box","false"); //在窗口上显示文本信息 SetDlgItemInt(IDC_EDIT_AGV, AgvValue); //在编辑框内显示平均灰度 SetDlgItemInt(IDC_EDIT_MIN, MinValue); //在编辑框内显示最小灰度 SetDlgItemInt(IDC_EDIT_MAX, MaxValue); //在编辑框内显示最大灰度 } else { DispObj(ho_ImageReduced, Handle2); DispText(Handle2, "OK", "window", "top", "left", "green", "box", "false"); //在窗口上显示文本 SetDlgItemInt(IDC_EDIT_AGV, AgvValue); //在编辑框内显示平均灰度 SetDlgItemInt(IDC_EDIT_MIN, MinValue); //在编辑框内显示最小灰度 SetDlgItemInt(IDC_EDIT_MAX, MaxValue); //在编辑框内显示最大灰度 } } }

最后看一下整体的效果: 在这里插入图片描述



【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭